package permit

/*******************************************************************************
Copyright:cloud
Author:cloudapex@126.com
Version:1.0
Date:2020-07-21
Description: 权限系统中间件
*******************************************************************************/
import (
	"gitee.com/cloudapex/permit/cache"
	"gitee.com/cloudapex/ulern/htp"
	"gitee.com/cloudapex/ulern/rds"
	"gitee.com/cloudapex/ulern/util"
	"github.com/gin-gonic/gin"
	ua "github.com/mileusna/useragent"
)

/*
 * 描述: 权限过滤中间件
 * 路由: top
 * 方法: 无
 *********************************************************************/
func MH_Permit(pool *rds.Pool, adminIds []int64) gin.HandlerFunc {
	UseRdb(pool)

	return func(c *gin.Context) {
		if cache.TheRdb != nil {

			uid := htp.CurrentUId(c)

			rPath := c.Request.URL.Path

			// load user's role
			role := cache.SUserRole{Id: uid}
			if err := role.Load(); err != nil {
				c.JSON(200, htp.RespErr(htp.CodePermitRdsRole, "CodePermitRdsRole", err))
				c.Abort()
				return
			}

			// check account conflict
			uDevce := c.GetHeader("User-Device")
			uAgent := ua.Parse(c.GetHeader("User-Agent"))
			if uDevce != "" && !role.Matched(uAgent.OS, uDevce) {
				c.JSON(200, htp.RespErr(htp.CodePermitLoginClash, "此账号已再其他设备登陆,您可通过再次登陆把对方踢下线.", nil))
				c.Abort()
				return
			}

			// check role changed
			if role.Upd == 1 {
				c.JSON(200, htp.RespErr(htp.CodePermitChanged, "你的账号权限发生变化,请重新登陆.", nil)) // 需要重新拉取权限数据
				c.Abort()
				return
			}

			// load route's role
			route := cache.HRouteRole{Route: rPath}
			if err := route.Load(); err != nil {
				c.JSON(200, htp.RespErr(htp.CodePermitRdsRoute, "CodePermitRdsRoute", err))
				c.Abort()
				return
			}

			// check permit
			effIds := checkPermit(&role, &route)
			if len(effIds) == 0 {
				// 检测超级系统管理员
				if !util.ContainI(uid, adminIds...) {
					c.JSON(200, htp.RespErr(htp.CodePermitDenied, "权限不足", nil))
					c.Abort()
					return
				}
			}

			// set datascope context
			scope := obtainDataScope(effIds, &route)
			c.Set(DEF_PERMIT_HEAD_FIELD, scope)
			c.Request.Header.Set(DEF_PERMIT_HEAD_FIELD, scope)
		}

		c.Next()
	}
}

// => PermitDataScope 获取
func CurrDataScope(c *gin.Context) string {
	scope := c.GetString(DEF_PERMIT_HEAD_FIELD)
	util.Cast(scope == "", func() { scope = c.Request.Header.Get(DEF_PERMIT_HEAD_FIELD) }, nil)
	return scope
}

// 检查权限(此用户拥有的所有角色id 匹配 此路由关联的角色s),返回匹配到的所有角色id
func checkPermit(role *cache.SUserRole, route *cache.HRouteRole) []int64 {
	if len(role.RIds) == 0 || len(route.RIds) == 0 {
		return nil
	}
	tmpm, effs := map[int64]int{}, []int64{}
	for _, id := range role.RIds {
		tmpm[id] = tmpm[id] + 1
	}
	for _, id := range route.RIds {
		tmpm[id] = tmpm[id] + 1
	}
	for id, it := range tmpm { // 某角色id对应的值大于1则认为
		if it > 1 {
			effs = append(effs, id)
		}
	}
	return effs
}
func obtainDataScope(rIds []int64, route *cache.HRouteRole) string {
	for n := len(route.Scopes) - 1; n >= 0; n-- {
		if util.ContainI(route.Scopes[n].RId, rIds...) {
			return route.Scopes[n].Scope
		}
	}
	return ""
}
